package ua.edu.nuos.jeetraining2012.cms.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ua.edu.nuos.jeetraining2012.cms.entity.StudentEntity;
import ua.edu.nuos.jeetraining2012.cms.entity.UserEntity;
import ua.edu.nuos.jeetraining2012.cms.model.StudentDAO;
import ua.edu.nuos.jeetraining2012.cms.model.exception.DAOException;
import ua.edu.nuos.jeetraining2012.cms.service.exception.ServiceException;
import ua.edu.nuos.jeetraining2012.cms.service.exception.ServiceValidationException;
import ua.edu.nuos.jeetraining2012.cms.util.interceptor.ShiroSecurity;

import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.ejb.Local;
import javax.ejb.Stateless;
import javax.validation.ConstraintViolation;
import javax.validation.ValidatorFactory;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Created with IntelliJ IDEA.
 * User: artur
 * Date: 16.06.13
 * Time: 12:42
 * To change this template use File | Settings | File Templates.
 */
@Stateless
@Local
@ShiroSecurity
public class Student {
    final private static Logger logger = LoggerFactory.getLogger(User.class);

    @SuppressWarnings({"EjbEnvironmentInspection"})
    @Resource
    private ValidatorFactory validatorFactory;

    @SuppressWarnings({"EjbEnvironmentInspection"})
    @EJB
    private StudentDAO dao;


    /**
     * Check if student is registered in storage by using user_id from DTO.
     * Return true if student is registered, false otherwise
     *
     * @param student StudentEntity to be searched for
     * @return True if user is registered, false otherwise
     * @throws ServiceException When underlying storage throw an exception
     */
    public boolean isExist(StudentEntity student) throws  ServiceException {
        return (findByUserId(student) != null);
    }


    /**
     * Lookup student in a storage and return DTO.
     * @param student StudentEntity to be searched for
     * @return dto with filled student values, null if not found
     * @throws ServiceException When DTO id is invalid
     */
    public StudentEntity findByUserId(StudentEntity student) throws ServiceException{
        logger.debug("Student findByUserId() - invocation");
        if (student == null)
            throw new IllegalArgumentException("DTO can't be null");

        try {
            return dao.findByUserId(student);
        } catch (DAOException e) {
            logger.error("Received DAO Exception", e);
            throw new ServiceException("Received DAO Exception: " + e.getMessage());
        }
    }

    /**
     * Method get the student profile from the storage.
     * @param student StudentEntity with user_id for which to get the data from the storage.
     * @return Collection with student data
     * @throws ServiceException When underlying storage throw an exception
     */
    public Map<String, Object> getStudentProfile(StudentEntity student) throws ServiceException {
        logger.debug("getStudentProfile - invocation");

        if (student == null) {
            throw new IllegalArgumentException("DTO can't be null");
        }

        Map<String, Object> studentData;
        try {
            boolean isExistStudent= false;
            if (isExist(student)){
                isExistStudent = true;
                student = findByUserId(student);
            }

            studentData = new HashMap<>();
            studentData.put("birthday", (isExistStudent)?new SimpleDateFormat("dd.MM.yyyy").format(student.getBirthday()):"");
            studentData.put("education", (isExistStudent)?student.getEducation():"");
            studentData.put("occupation", (isExistStudent) ? student.getOccupation() : "");
            studentData.put("photo", (isExistStudent)?student.getPhoto():"");
            studentData.put("phone", (isExistStudent)?student.getPhone():"");
            studentData.put("skype", (isExistStudent)?student.getSkype():"");
        } catch (ServiceException e) {
            logger.warn("Method getStudentProfile() - finish with ServiceException: "+e.getMessage());
            throw new ServiceException("Method finish with ServiceException Msg: "+e.getMessage());
        }

        logger.debug("getStudentProfile() - finish");
        return studentData;
    }

    /**
     * Persist student in storage. If this is new user, new entry will be added otherwise existed student is updated
     * @param studentEntity StudentEntity to be persisted
     * @throws ServiceValidationException When StudentEntity values are invalid
     * @throws ServiceException When underlying storage throw an exception
     */
    public void persist(StudentEntity studentEntity) throws ServiceValidationException, ServiceException{
        logger.debug("Method persist() Student - invocation");
        if (studentEntity == null){
            logger.warn("Method persist() Student - finish with IllegalArgumentException");
            throw new IllegalArgumentException("DTO can't be null");
        }


        boolean exist = isExist(studentEntity);
        Set<ConstraintViolation<StudentEntity>> validationResult = validatorFactory.getValidator().validate(studentEntity);
        if (!validationResult.isEmpty()) {
            logger.warn("ServiceValidationResult - "+validationResult);
            throw new ServiceValidationException(validationResult);
        }
        try {
            if (exist) {
                dao.update(studentEntity);
            } else {
                dao.create(studentEntity);
            }
        } catch (DAOException e) {
            logger.error("User persist received DAO Exception", e);
            throw new ServiceException("User persist received DAO Exception: " + e.getMessage());
        }

        logger.debug("Method persist() - finish");
    }

    /**
     * Check profiles required fields filled in.
     * <p/>
     * Return <code>true</code>, if all necessary fields were filled by User, in other cases, return <code>false</code>.
     * <p/>
     * If user ID is null or empty, IllegalArgumentException will be thrown.
     *
     * @param userId                    User ID, whose profile should be checked.
     * @return                          True if all necessary fields are filled well, either, return false.
     */
    public boolean isProfileOk(String userId) {
        logger.debug("isProfileOk() - started.");

        if (userId == null || userId.isEmpty()) {
            logger.error("User id can't be {}", userId);
            logger.debug("isProfileOk() - finished with IllegalArgumentException.");
            throw new IllegalArgumentException("UserId can't be null or empty");
        }

        boolean isProfileOk = false;
        UserEntity userEntity = new UserEntity();
        userEntity.setId(userId);
        StudentEntity searchEntity = new StudentEntity();
        searchEntity.setUserId(userEntity);
        logger.debug("Trying to check filled profile.");
        try {
            StudentEntity entity = dao.findByUserId(searchEntity);
            logger.info("Found entity is {} ", entity);

            if (entity != null && entity.getPhone() != null && !entity.getPhone().isEmpty()
                    && entity.getEducation() != null && !entity.getEducation().isEmpty()
                    && entity.getBirthday() != null) {
                isProfileOk = true;

            }
        } catch (DAOException e) {
            logger.error("Can't find any Student record. Got DAOException with message: {} and \ntrace:\n {}",
                    e.getMessage(), e.getStackTrace());
            logger.debug("False will be returned.");
        }

        logger.debug("isProfileOk() - finished.");
        return isProfileOk;
    }
}
